home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / graphics / font3d10.zip / truetype.cpp < prev    next >
C/C++ Source or Header  |  1994-09-15  |  40KB  |  954 lines

  1. //===========================================================================================================
  2. //  TrueType.CPP
  3. //
  4. //  Copyright (c) 1994 by Todd A. Prater
  5. //  All rights reserved.
  6. //
  7. //===========================================================================================================
  8.  
  9. #include <stdlib.h>
  10. #include <fstream.h>
  11. #include "Config.H"
  12. #include "Array.H"
  13. #include "Geometry.H"
  14. #include "TrueType.H"
  15.  
  16.  
  17.  
  18. //===========================================================================================================
  19. //  TTFont                                                                                         (PUBLIC)
  20. //-----------------------------------------------------------------------------------------------------------
  21. //  This is the constructor for the TTFont class.  It opens the font file given by 'filename', and reads
  22. //  the information it needs into its internal data structures.
  23. //===========================================================================================================
  24.  
  25.  
  26. TTFont::TTFont(CHARPTR filename)
  27. {
  28.  
  29.    ULONG  c,i,j,k,gi;             // A few counters.
  30.    ULONG  pos;                    // A placekeeper for the fontdata array.
  31.    LONG   dx,dy,tx,ty;            // Used in translating from relative to absolute coordinates.
  32.  
  33.    USHORT tabledirsize;           // Size of the Table Directory.
  34.    ULONG  tabledatasize;          // Size of the data contained in all the tables combined.
  35.    ULONG  fontdatasize;           // Size of the entire font file.
  36.    ULONG  tempts;                 // Temporarily holds the length of a table.
  37.  
  38.    BYTE* tfd;                     // This will temporarily hold the first twelve bytes of the font file.
  39.    BYTE* tabledir;                // This will temporarily hold the table directory of the font.
  40.  
  41.    ULONG  cmapTableOffset;        // Offset of the 'cmap' table
  42.    ULONG  cmapTableLength;        // Length of the 'cmap' table
  43.    ULONG  glyfTableOffset;        // Offset of the 'glyf' table
  44.    ULONG  glyfTableLength;        // Length of the 'glyf' table
  45.    ULONG  headTableOffset;        // Offset of the 'head' table
  46.    ULONG  headTableLength;        // Length of the 'head' table
  47.    ULONG  locaTableOffset;        // Offset of the 'loca' table
  48.    ULONG  locaTableLength;        // Length of the 'loca' table
  49.    ULONG  maxpTableOffset;        // Offset of the 'maxp' table
  50.    ULONG  maxpTableLength;        // Length of the 'maxp' table
  51.    ULONG  nameTableOffset;        // Offset of the 'name' table
  52.    ULONG  nameTableLength;        // Length of the 'name' table
  53.  
  54.    Fixed  sfnt_version;           // Used to read the Offset Table
  55.    USHORT numTables;              //  .
  56.    USHORT searchRange;            //  .
  57.    USHORT entrySelector;          //  .
  58.    USHORT rangeShift;
  59.  
  60.    SHORT  indexToLocFormat;       // Which format the data in the 'loca' table is in (SHORT or LONG)
  61.  
  62.    USHORT numNameRecords;                           // Used in decoding the naming table 'name'
  63.    USHORT stringStorageOffset;                      //  .
  64.    USHORT platformID;                               //  .
  65.    USHORT specificID;                               //  .
  66.    USHORT languageID;
  67.    USHORT nameID;
  68.    USHORT stringLength;
  69.    USHORT stringOffset;
  70.  
  71.    ULONG  offset;                                   // Used in decoding the glyph offset table
  72.    ULONG* glyphOffsetArray;
  73.  
  74.    USHORT  numCmapSubtables;                        // Used in decoding the 'cmap' table
  75.    ULONG   cmapSubtableOffset;                      //  .
  76.    ULONG   cmapSubtableStart;                       //  .
  77.    USHORT  cmapSubtableLength;                      //  .
  78.    USHORT  cmapSubtableSegCount;
  79.    USHORT  cmapSubtableLastCharacter;
  80.    USHORT* cmapSubtableEndCount;
  81.    USHORT* cmapSubtableStartCount;
  82.    USHORT* cmapSubtableIdDelta;
  83.    USHORT* cmapSubtableIdRangeOffset;
  84.    ULONG   cmapSubtableIdRangeOffsetArrayAddress;
  85.    ULONG   index;
  86.    ULONG   seg;
  87.    BYTE    found;
  88.  
  89.    USHORT  repeatcount;                             // Used in decoding the 'glyf' table
  90.    USHORT* endPtsOfContours;                        //  .
  91.    SHORT   numberOfContours;                        //  .
  92.    SHORT   xMin;                                    //  .
  93.    SHORT   yMin;
  94.    SHORT   xMax;
  95.    SHORT   yMax;
  96.    USHORT  numberOfPoints;
  97.    USHORT  instructionLength;
  98.    BYTE*   flags;
  99.    SHORT   xWord;
  100.    SHORT   yWord;
  101.    SHORT   xByte;
  102.    SHORT   yByte;
  103.    SHORT   lastx;
  104.    SHORT   lasty;
  105.    USHORT  startPoint;
  106.    USHORT  endPoint;
  107.    BYTE    currentFlag;
  108.    ULONG   endOfXData;
  109.  
  110.    BYTE    tempbyte;
  111.    CHAR    tempchar;
  112.    SHORT   tempshort;
  113.    USHORT  tempushort;
  114.    LONG    templong;
  115.    ULONG   tempulong;
  116.    Fixed   tempfixed;
  117.  
  118.  
  119.  
  120.  
  121.    copyrightString=NULL;
  122.    familyString=NULL;
  123.    subfamilyString=NULL;
  124.    idString=NULL;
  125.    fullnameString=NULL;
  126.    versionString=NULL;
  127.    psnameString=NULL;
  128.    trademarkString=NULL;
  129.    
  130.    // ____ Create an input file stream, associate it with the font file we're reading in, ____
  131.    // ____ and set it to read in binary mode.  Also, make sure it doesn't ignore spaces.  ____
  132.  
  133.  
  134.    #ifdef __GNUC__
  135.       ifstream inputfile((char*)filename);
  136.    #else
  137.       ifstream inputfile((char*)filename,ios::binary);
  138.    #endif
  139.  
  140.    if (!inputfile)
  141.    {
  142.       cout<<"ERROR:  Unable to open '"<<filename<<"'\n";
  143.       exit(1);
  144.    }
  145.    inputfile.unsetf(ios::skipws);
  146.  
  147.    // ____ Create an array to temporarily hold the Offset Table.                          ____
  148.  
  149.    tfd = new BYTE[OFFSET_TABLE_SIZE];
  150.  
  151.    // ____ Read in the Offset Table of the font file.  Among other things, it contains    ____
  152.    // ____ the number of table entries (and tables) to follow.                            ____
  153.  
  154.    for (i=0;i<OFFSET_TABLE_SIZE;i++)
  155.       inputfile>>tfd[i];
  156.  
  157.    // ____ Together, bytes 4 and 5 describe the number of entries that follow in the      ____
  158.    // ____ Table Directory.                                                               ____
  159.  
  160.    numTables = toUSHORT(tfd[4],tfd[5]);
  161.  
  162.    // ____ Now that we know how many tables there are, we can calculate the size of the   ____
  163.    // ____ Table Directory, since each entry contains four ULONG's.                     ____
  164.  
  165.    tabledirsize = sizeof(ULONG)*4*numTables;
  166.  
  167.    // ____ And, make an array to hold the Table Directory data temporarily.               ____
  168.  
  169.    tabledir = new BYTE[tabledirsize];  // delete this...
  170.  
  171.    // ____ Next, store the Table Directory in the temporary array.  Each entry contains   ____
  172.    // ____ the length of that particular table, so keep track of the combined length of   ____
  173.    // ____ all the tables while we're at it.  Each loop iteration reads in 16 bytes.      ____
  174.    // ____ Note that all tables are long aligned in the file itself, but the lengths      ____
  175.    // ____ given in the Table Directory are the actual lengths of the table data.  Any    ____
  176.    // ____ length not a multiple of four must be rounded up.                              ____
  177.  
  178.    tabledatasize=0;
  179.    for (i=0;i<tabledirsize;i=i+16)
  180.    {
  181.       inputfile>>tabledir[i]>>tabledir[i+1]>>tabledir[i+2]>>tabledir[i+3];
  182.       inputfile>>tabledir[i+4]>>tabledir[i+5]>>tabledir[i+6]>>tabledir[i+7];
  183.       inputfile>>tabledir[i+8]>>tabledir[i+9]>>tabledir[i+10]>>tabledir[i+11];
  184.       inputfile>>tabledir[i+12]>>tabledir[i+13]>>tabledir[i+14]>>tabledir[i+15];
  185.  
  186.       tempts = toULONG(tabledir[i+12],tabledir[i+13],tabledir[i+14],tabledir[i+15]);
  187.       if ((tempts/4)*4 != tempts) tempts = (tempts/4+1)*4;
  188.       tabledatasize += tempts;
  189.    }
  190.  
  191.    // ____ Now we know enough information to calculate the size of the entire font file.  ____
  192.  
  193.    fontdatasize = OFFSET_TABLE_SIZE+tabledirsize+tabledatasize;
  194.  
  195.    // ____ And, create an array to hold the entire font file.                             ____
  196.  
  197.    #ifdef __MSDOS__
  198.       ARRAY<BYTE> fontdata(fontdatasize);
  199.    #else
  200.       BYTE* fontdata = new BYTE[fontdatasize];
  201.    #endif
  202.  
  203.    // ____ Put all of the information we temporarily stored, into the new font data       ____
  204.    // ____ array, and delete the temporary storage space since we won't need it anymore.  ____
  205.  
  206.    for (i=0;i<OFFSET_TABLE_SIZE;i++)
  207.       fontdata[i]=tfd[i];
  208.    for (i=OFFSET_TABLE_SIZE;i<OFFSET_TABLE_SIZE+tabledirsize;i++)
  209.       fontdata[i]=tabledir[i-OFFSET_TABLE_SIZE];
  210.  
  211.    delete tfd;
  212.  
  213.    // ____ Read in the rest of the font file.                                             ____
  214.  
  215.    for (i=OFFSET_TABLE_SIZE+tabledirsize;i<fontdatasize;i++)
  216.    {
  217.       inputfile>>fontdata[i];
  218.    }
  219.  
  220.    // ____ Close the font file.                                                           ____
  221.  
  222.    inputfile.close();
  223.  
  224.    // ____ At this point, we have read the font file into memory.  Now we turn to the     ____
  225.    // ____ task of deciphering it....                                                     ____
  226.  
  227.    pos = 0;
  228.  
  229.    // ____ The only thing we need in the Offset Table is the number of tables, which we   ____
  230.    // ____ we have already found, so skip over it now.                                    ____
  231.  
  232.    pos+=sizeof(Fixed);
  233.    pos+=4*sizeof(USHORT);
  234.  
  235.    // ____ The only tables we will need to look at are: cmap, glyf, head, loca, maxp,     ____
  236.    // ____ and name.  Since the entries in the Table Directory are in alphabetical        ____
  237.    // ____ order, we can search for them one at a time, getting the information in each   ____
  238.    // ____ one as necessary.  All of the tables are required, so they SHOULD be there.    ____
  239.  
  240.    while (   fontdata[pos]  !='c'                  // Search for the 'cmap' table entry
  241.           || fontdata[pos+1]!='m'
  242.           || fontdata[pos+2]!='a'
  243.           || fontdata[pos+3]!='p')  pos+=16;
  244.  
  245.    cmapTableOffset = toULONG(fontdata[pos+8],fontdata[pos+9],fontdata[pos+10],fontdata[pos+11]);
  246.    cmapTableLength = toULONG(fontdata[pos+12],fontdata[pos+13],fontdata[pos+14],fontdata[pos+15]);
  247.    pos+=16;
  248.  
  249.    while (   fontdata[pos]  !='g'                  // Search for the 'glyf' table entry
  250.           || fontdata[pos+1]!='l'
  251.           || fontdata[pos+2]!='y'
  252.           || fontdata[pos+3]!='f')  pos+=16;
  253.  
  254.    glyfTableOffset = toULONG(fontdata[pos+8],fontdata[pos+9],fontdata[pos+10],fontdata[pos+11]);
  255.    glyfTableLength = toULONG(fontdata[pos+12],fontdata[pos+13],fontdata[pos+14],fontdata[pos+15]);
  256.    pos+=16;
  257.  
  258.    while (   fontdata[pos]  !='h'                  // Search for the 'head' table entry
  259.           || fontdata[pos+1]!='e'
  260.           || fontdata[pos+2]!='a'
  261.           || fontdata[pos+3]!='d')  pos+=16;
  262.  
  263.    headTableOffset = toULONG(fontdata[pos+8],fontdata[pos+9],fontdata[pos+10],fontdata[pos+11]);
  264.    headTableLength = toULONG(fontdata[pos+12],fontdata[pos+13],fontdata[pos+14],fontdata[pos+15]);
  265.    pos+=16;
  266.  
  267.    while (   fontdata[pos]  !='l'                  // Search for the 'loca' table entry
  268.           || fontdata[pos+1]!='o'
  269.           || fontdata[pos+2]!='c'
  270.           || fontdata[pos+3]!='a')  pos+=16;
  271.  
  272.    locaTableOffset = toULONG(fontdata[pos+8],fontdata[pos+9],fontdata[pos+10],fontdata[pos+11]);
  273.    locaTableLength = toULONG(fontdata[pos+12],fontdata[pos+13],fontdata[pos+14],fontdata[pos+15]);
  274.    pos+=16;
  275.  
  276.    while (   fontdata[pos]  !='m'                  // Search for the 'maxp' table entry
  277.           || fontdata[pos+1]!='a'
  278.           || fontdata[pos+2]!='x'
  279.           || fontdata[pos+3]!='p')  pos+=16;
  280.  
  281.    maxpTableOffset = toULONG(fontdata[pos+8],fontdata[pos+9],fontdata[pos+10],fontdata[pos+11]);
  282.    maxpTableLength = toULONG(fontdata[pos+12],fontdata[pos+13],fontdata[pos+14],fontdata[pos+15]);
  283.    pos+=16;
  284.  
  285.    while (   fontdata[pos]  !='n'                  // Search for the 'name' table entry
  286.           || fontdata[pos+1]!='a'
  287.           || fontdata[pos+2]!='m'
  288.           || fontdata[pos+3]!='e')  pos+=16;
  289.  
  290.    nameTableOffset = toULONG(fontdata[pos+8],fontdata[pos+9],fontdata[pos+10],fontdata[pos+11]);
  291.    nameTableLength = toULONG(fontdata[pos+12],fontdata[pos+13],fontdata[pos+14],fontdata[pos+15]);
  292.    pos+=16;
  293.  
  294.    // ____ Now we know the offset and length of each of the tables we will need in the    ____
  295.    // ____ font file.  Now we can start the processing of each table.                     ____
  296.  
  297.    //==========================================================================================
  298.    // ____ We begin with the Font Header Table: 'head'.  The only two pieces of informa-  ____
  299.    // ____ tion we need are 'indexToLocFormat, which specifies the data type of the       ____
  300.    // ____ offsets used in the 'loca' table, and 'unitsPerEm' which specifies the number  ____
  301.    // ____ of units in the 'Em Square'.                                                   ____
  302.    //==========================================================================================
  303.  
  304.    pos = headTableOffset + 18;
  305.    unitsPerEm = toUSHORT(fontdata[pos],fontdata[pos+1]);
  306.  
  307.    pos = headTableOffset + 50;    
  308.    indexToLocFormat = toSHORT(fontdata[pos],fontdata[pos+1]);
  309.  
  310.    //==========================================================================================
  311.    // ____ Next is the Maximum Profile Table: 'maxp'.  The values we need here are the    ____
  312.    // ____ number of glyphs in the font file, the maximum number of points per glyph,     ____
  313.    // ____ and the maximum number of contours per glyph.                                  ____
  314.    //==========================================================================================
  315.  
  316.    pos = maxpTableOffset + 4;
  317.    numGlyphs = toUSHORT(fontdata[pos],fontdata[pos+1]);
  318.  
  319.    // ____ Go ahead and create the glyph array now, we'll fill it in later.               ____
  320.  
  321.    glyphs = new TTGlyph[numGlyphs];
  322.  
  323.    pos = maxpTableOffset + 6;
  324.    maxPoints = toUSHORT(fontdata[pos],fontdata[pos+1]);
  325.  
  326.    pos = maxpTableOffset + 8;
  327.    maxContours = toUSHORT(fontdata[pos],fontdata[pos+1]);
  328.  
  329.  
  330.    //==========================================================================================
  331.    // ____ Third, is the Naming Table: 'name'.  There are up to eight strings contained   ____
  332.    // ____ here:  copyright notice, font family name, font subfamily name, a unique font  ____
  333.    // ____ identifier, full font name, version, postscript name, and trademark.  Memory   ____
  334.    // ____ for each string is allocated as needed.                                        ____
  335.    //==========================================================================================
  336.  
  337.    // ____ Find the number of name records (ie. strings) in the Naming Table.             ____
  338.  
  339.    pos = nameTableOffset + 2;
  340.    numNameRecords = toUSHORT(fontdata[pos],fontdata[pos+1]);
  341.  
  342.    // ____ Find the offset from the beginning of the Naming Table to the beginning of the ____
  343.    // ____ string storage area.                                                           ____
  344.  
  345.    pos = nameTableOffset + 4;
  346.    stringStorageOffset = toUSHORT(fontdata[pos],fontdata[pos+1]);
  347.  
  348.    // ____ Go through each name record in the table and find the ones that are for        ____
  349.    // ____ Windows/OS/2 computers (platformID==3), ASCII (specificID==1), and in English  ____
  350.    // ____ (languageID==1033).  Once we have one that fits that description, determine    ____
  351.    // ____ which of the eight possible name strings it is (ie. copyright, family, etc...) ____
  352.    // ____ and make a null-terminated, ASCII string out of it.  All the strings that have ____
  353.    // ____ a platformID of 3 are in Unicode (two-byte characters), but, for our purposes, ____
  354.    // ____ we can just use the low byte for each character.  This is because ASCII and    ____
  355.    // ____ Unicode match for most ASCII characters.  In the code, this is done by ignor-  ____
  356.    // ____ ing every other byte in the string.                                            ____
  357.  
  358.    pos = nameTableOffset + 6;
  359.    while (pos<(nameTableOffset+stringStorageOffset))
  360.    {
  361.       platformID   = toUSHORT(fontdata[pos   ],fontdata[pos+1 ]);
  362.       specificID   = toUSHORT(fontdata[pos+2 ],fontdata[pos+3 ]);
  363.       languageID   = toUSHORT(fontdata[pos+4 ],fontdata[pos+5 ]);
  364.       nameID       = toUSHORT(fontdata[pos+6 ],fontdata[pos+7 ]);
  365.       stringLength = toUSHORT(fontdata[pos+8 ],fontdata[pos+9 ]);
  366.       stringOffset = toUSHORT(fontdata[pos+10],fontdata[pos+11]);
  367.  
  368.       if ( platformID==3 && specificID==1 && languageID==1033 )
  369.       {
  370.          switch (nameID)
  371.          {
  372.             case 0:  
  373.                copyrightString = new CHAR[stringLength/2+1];
  374.                for(i=1;i<stringLength;i+=2)
  375.                   copyrightString[i/2]=fontdata[nameTableOffset+stringStorageOffset+stringOffset+i];
  376.                copyrightString[i/2]=0;
  377.                break;
  378.  
  379.             case 1:  
  380.                familyString = new CHAR[stringLength/2+1];
  381.                for(i=1;i<stringLength;i+=2)
  382.                   familyString[i/2]=fontdata[nameTableOffset+stringStorageOffset+stringOffset+i];
  383.                familyString[i/2]=0;
  384.                break;
  385.  
  386.             case 2:  
  387.                subfamilyString = new CHAR[stringLength/2+1];
  388.                for(i=1;i<stringLength;i+=2)
  389.                   subfamilyString[i/2]=fontdata[nameTableOffset+stringStorageOffset+stringOffset+i];
  390.                subfamilyString[i/2]=0;
  391.                break;
  392.  
  393.             case 3:  
  394.                idString = new CHAR[stringLength/2+1];
  395.                for(i=1;i<stringLength;i+=2)
  396.                   idString[i/2]=fontdata[nameTableOffset+stringStorageOffset+stringOffset+i];
  397.                idString[i/2]=0;
  398.                break;
  399.  
  400.             case 4:  
  401.                fullnameString = new CHAR[stringLength/2+1];
  402.                for(i=1;i<stringLength;i+=2)
  403.                   fullnameString[i/2]=fontdata[nameTableOffset+stringStorageOffset+stringOffset+i];
  404.                fullnameString[i/2]=0;
  405.                break;
  406.  
  407.             case 5:  
  408.                versionString = new CHAR[stringLength/2+1];
  409.                for(i=1;i<stringLength;i+=2)
  410.                   versionString[i/2]=fontdata[nameTableOffset+stringStorageOffset+stringOffset+i];
  411.                versionString[i/2]=0;
  412.                break;
  413.  
  414.             case 6:  
  415.                psnameString = new CHAR[stringLength/2+1];
  416.                for(i=1;i<stringLength;i+=2)
  417.                   psnameString[i/2]=fontdata[nameTableOffset+stringStorageOffset+stringOffset+i];
  418.                psnameString[i/2]=0;
  419.                break;
  420.  
  421.             case 7:  
  422.                trademarkString = new CHAR[stringLength/2+1];
  423.                for(i=1;i<stringLength;i+=2)
  424.                   trademarkString[i/2]=fontdata[nameTableOffset+stringStorageOffset+stringOffset+i];
  425.                trademarkString[i/2]=0;
  426.                break;
  427.  
  428.          }
  429.       }
  430.       pos+=12;
  431.    }
  432.  
  433.  
  434.    //==========================================================================================
  435.    // ____ Fourth, is the Index to Location Table: 'loca'.  It stores the offsets to each ____
  436.    // ____ of the glyphs in the font, relative to the beginning of the Glyph Data Table.  ____
  437.    // ____ Also implied in this information is the length of each of the glyph elements,  ____
  438.    // ____ and for this reason, there is an extra number at the end of the table that     ____
  439.    // ____ gives the length of the last glyph.  There are two versions of this table, one ____
  440.    // ____ short and one long.  Which version is present is specified in the              ____
  441.    // ____ indexToLocFormat entry in the 'head' table.                                    ____
  442.    //==========================================================================================
  443.  
  444.    pos=locaTableOffset;
  445.  
  446.    glyphOffsetArray = new ULONG[numGlyphs+1];
  447.  
  448.    for (i=0;i<numGlyphs+1;i++)
  449.    {
  450.       if (indexToLocFormat==0)
  451.       {
  452.          // __ In the short format, offset/2 is stored, so offset*2 is the actual offset __
  453.  
  454.          offset=(ULONG)toUSHORT(fontdata[pos],fontdata[pos+1]);
  455.          offset=offset*2;        
  456.          pos+=2; 
  457.       }
  458.       else
  459.       {
  460.          // __ In the long format, the actual offset is stored __
  461.  
  462.          offset=toULONG(fontdata[pos],fontdata[pos+1],fontdata[pos+2],fontdata[pos+3]);
  463.          pos+=4;
  464.       }
  465.  
  466.       glyphOffsetArray[i]=offset;
  467.  
  468.    }
  469.  
  470.  
  471.    //==========================================================================================
  472.    // ____ Fifth, is the Character to Glyph Index Mapping Table: 'cmap'.  This table      ____
  473.    // ____ defines the mapping of character codes to the glyph index values used in the   ____
  474.    // ____ font.  Although more than one mapping may be present, we will only use the     ____
  475.    // ____ Microsoft UGL encoding subtable.                                               ____
  476.    //==========================================================================================
  477.  
  478.    // ____ Get the number of subtables in this table.                                     ____
  479.  
  480.    pos = cmapTableOffset+2;
  481.    numCmapSubtables = toUSHORT(fontdata[pos],fontdata[pos+1]);
  482.  
  483.    // ____ Look through the list of subtable entries for one with a platformID of 3, and  ____
  484.    // ____ a specificID of 1.  This is the table with Microsoft UGL encodings.            ____
  485.  
  486.    found = 0;
  487.    pos = cmapTableOffset+4;
  488.    while (pos<(cmapTableOffset+4+numCmapSubtables*8))
  489.    {
  490.       platformID=toUSHORT(fontdata[pos],fontdata[pos+1]);
  491.       specificID=toUSHORT(fontdata[pos+2],fontdata[pos+3]);
  492.       cmapSubtableOffset = toULONG(fontdata[pos+4],fontdata[pos+5],fontdata[pos+6],fontdata[pos+7]);
  493.       if (platformID==3 && specificID==1)
  494.       {
  495.          found=1;
  496.          break;
  497.       }
  498.       else pos+=8;
  499.    }
  500.  
  501.    if (!found)
  502.    {
  503.       cout<<"ERROR: This font file doesn't have a Microsoft UGL character encoding table."<<endl;
  504.       cout<<"       Unable to continue.  Aborting."<<endl;
  505.       exit(1);
  506.    }
  507.  
  508.    // ____ Calculate the offset of the start of the Microsoft UGL subtable                ____
  509.  
  510.    cmapSubtableStart = cmapTableOffset+cmapSubtableOffset;
  511.  
  512.    // ____ Find the length of the subtable, and the number of segments in it.             ____
  513.  
  514.    pos = cmapSubtableStart+2;
  515.    cmapSubtableLength = toUSHORT(fontdata[pos],fontdata[pos+1]);
  516.    pos = cmapSubtableStart+6;
  517.    cmapSubtableSegCount = toUSHORT(fontdata[pos],fontdata[pos+1])/2;
  518.  
  519.    // ____ Read in the array of Ending Character codes for each of the segments.          ____
  520.  
  521.    cmapSubtableEndCount = new USHORT[cmapSubtableSegCount];
  522.    pos = cmapSubtableStart+14;
  523.    for(i=0;i<cmapSubtableSegCount*2;i+=2)
  524.       cmapSubtableEndCount[i/2]=toUSHORT(fontdata[pos+i],fontdata[pos+i+1]);
  525.    pos+=i;
  526.  
  527.    pos+=2;  // Eat up the reserved padding word.
  528.  
  529.    // ____ Read in the array of Beginning Character codes for each of the segments        ____
  530.  
  531.    cmapSubtableStartCount = new USHORT[cmapSubtableSegCount];
  532.    for(i=0;i<cmapSubtableSegCount*2;i+=2)
  533.       cmapSubtableStartCount[i/2]=toUSHORT(fontdata[pos+i],fontdata[pos+i+1]);
  534.    pos+=i;
  535.  
  536.    // ____ Read in the Delta value for each segment.                                      ____
  537.  
  538.    cmapSubtableIdDelta = new USHORT[cmapSubtableSegCount];
  539.    for(i=0;i<cmapSubtableSegCount*2;i+=2)
  540.       cmapSubtableIdDelta[i/2]=toUSHORT(fontdata[pos+i],fontdata[pos+i+1]);
  541.    pos+=i;
  542.  
  543.    // ____ Read in the Offset into the GlyphIdArray for each segment.                     ____
  544.  
  545.    cmapSubtableIdRangeOffsetArrayAddress = pos;
  546.    cmapSubtableIdRangeOffset = new USHORT[cmapSubtableSegCount];
  547.    for(i=0;i<cmapSubtableSegCount*2;i+=2)
  548.       cmapSubtableIdRangeOffset[i/2]=toUSHORT(fontdata[pos+i],fontdata[pos+i+1]);
  549.    pos+=i;
  550.  
  551.    // ____ Now use the values we've just looked up to calculate the glyph index of each   ____
  552.    // ____ character 0-255.  Details on how this is done can be found in the technical    ____
  553.    // ____ description of the font file given in 'TrueType Font Files' by the Microsoft   ____
  554.    // ____ Corporation.                                                                   ____
  555.  
  556.    for(c=0;c<256;c++)
  557.    {
  558.       for(seg=0;seg<cmapSubtableSegCount;seg++)
  559.          if(cmapSubtableEndCount[seg]>=c) break;
  560.  
  561.       if (cmapSubtableStartCount[seg]>c)
  562.          characterMap[c]=0;
  563.       else
  564.       {
  565.          if (cmapSubtableIdRangeOffset[seg]==0)
  566.             characterMap[c] = (USHORT)(cmapSubtableIdDelta[seg]+c);
  567.          else
  568.          {
  569.             index = cmapSubtableIdRangeOffset[seg]
  570.                   + (c-cmapSubtableStartCount[seg])*2
  571.                   + cmapSubtableIdRangeOffsetArrayAddress+seg*2;
  572.             characterMap[c] = toUSHORT(fontdata[index],fontdata[index+1]);
  573.          }
  574.       }
  575.    } 
  576.  
  577.    delete cmapSubtableEndCount;                          // We won't be needing these anymore.
  578.    delete cmapSubtableStartCount;
  579.    delete cmapSubtableIdDelta;
  580.    delete cmapSubtableIdRangeOffset;
  581.  
  582.  
  583.    //==========================================================================================
  584.    // ____ Finally, our last table contains the glyph data: 'glyf'.                       ____
  585.    //==========================================================================================
  586.  
  587.    // ___ Allocate enough space for all the glyphs in the font                            ____
  588.  
  589.    glyphs = new TTGlyph[numGlyphs];
  590.    if (!glyphs)
  591.    {
  592.       cout<<"ERROR: Out of memory."<<endl;
  593.       exit(1);
  594.    }
  595.  
  596.    for(gi=0;gi<numGlyphs;gi++)
  597.    {
  598.       // ____ If the offset of this glyph is the same as the next one, then that means    ____
  599.       // ____ the glyph has no contours.  We can go ahead and skip the rest of this       ____
  600.       // ____ iteration.  Otherwise, calculate the glyph's offset into the font file.     ____
  601.  
  602.       if ((gi<numGlyphs-1) && (glyphOffsetArray[gi]==glyphOffsetArray[gi+1]))
  603.          continue;
  604.       else
  605.          pos = glyfTableOffset + glyphOffsetArray[gi];
  606.  
  607.       // ____ Read the glyph header.                                                      ____
  608.  
  609.       numberOfContours  = toSHORT(fontdata[pos],fontdata[pos+1]);  pos+=2;
  610.       xMin              = toSHORT(fontdata[pos],fontdata[pos+1]);  pos+=2;
  611.       yMin              = toSHORT(fontdata[pos],fontdata[pos+1]);  pos+=2;
  612.       xMax              = toSHORT(fontdata[pos],fontdata[pos+1]);  pos+=2;
  613.       yMax              = toSHORT(fontdata[pos],fontdata[pos+1]);  pos+=2;
  614.  
  615.       // ____ Fill in the glyph's data fields.                                            ____
  616.  
  617.       glyphs[gi].numContours = numberOfContours;
  618.       glyphs[gi].xMin        = xMin;
  619.       glyphs[gi].yMin        = yMin;
  620.       glyphs[gi].xMax        = xMax;
  621.       glyphs[gi].yMax        = yMax;
  622.  
  623.       // ____ Only continue processing this glyph if it is a simple glyph (not a          ____
  624.       // ____ composite).                                                                 ____
  625.  
  626.       if (numberOfContours>0)
  627.       {
  628.          // ____ Create an array to hold the end points of all the contours in the glyph. ____
  629.  
  630.          endPtsOfContours = new USHORT[numberOfContours];
  631.          if(!endPtsOfContours)
  632.          {
  633.             cout<<"ERROR: Out of memory."<<endl;
  634.             exit(1);
  635.          }
  636.  
  637.          // ____ Read in the end point information from the glyph table.                  ____
  638.  
  639.          for(i=0;i<numberOfContours;i++)
  640.          {
  641.             endPtsOfContours[i]=toUSHORT(fontdata[pos],fontdata[pos+1]); pos+=2;
  642.          }
  643.  
  644.          // ____ Allocate memory for each of the contours in the glyph.                   ____
  645.  
  646.          glyphs[gi].contours = new TTContour[numberOfContours];
  647.          if(!glyphs[gi].contours)
  648.          {
  649.             cout<<"ERROR: Out of memory."<<endl;
  650.             exit(1);
  651.          }
  652.  
  653.          // ____ Calculate the total number of points in this glyph (all contours).       ____
  654.  
  655.          numberOfPoints    = endPtsOfContours[numberOfContours-1]+1;
  656.  
  657.          // ____ Read in the length of the instructions contained in the table for this   ____
  658.          // ____ particular glyph.                                                        ____
  659.  
  660.          instructionLength = toUSHORT(fontdata[pos],fontdata[pos+1]); pos+=2;
  661.  
  662.          // ____ Skip over the instructions.                                              ____
  663.  
  664.          pos+=instructionLength;
  665.  
  666.          // ____ Allocate space for an array of flags, one for each point in the glyph.   ____
  667.  
  668.          flags = new BYTE[numberOfPoints];
  669.          if(!flags)
  670.          {
  671.             cout<<"ERROR: Out of memory."<<endl;
  672.             exit(1);
  673.          }
  674.  
  675.          // ____ Read in the flags for this glyph.  The outer loop gathers the flags that ____
  676.          // ____ are actually contained in the table.  If the repeat bit is set in a flag ____
  677.          // ____ then the next byte is read from the table; this is the number of times   ____
  678.          // ____ to repeat the last flag.  The inner loop does this, incrementing the     ____
  679.          // ____ outer loops index each time.                                             ____
  680.  
  681.          for(i=0;i<numberOfPoints;i++)
  682.          {
  683.             flags[i]=fontdata[pos]; pos++;
  684.             if (isBitSet(flags[i],3))
  685.             {
  686.                repeatcount=fontdata[pos];pos++;
  687.                for(;repeatcount>0;repeatcount--)
  688.                {
  689.                   i++;
  690.                   flags[i]=flags[i-1];
  691.                }
  692.             }
  693.          }
  694.  
  695.          // ____ Now come the x- and y-coordinate data.  The font file stores all coord-  ____
  696.          // ____ inates as relative to the previous one.  This is how we read them in     ____
  697.          // ____ initially; we will convert to absolute coords later.  The x- and y-      ____
  698.          // ____ coordinates come separately, so we will have to have separate loops for  ____
  699.          // ____ each one.  Each outer loop iteration will read in a contour, while the   ____
  700.          // ____ inner loop reads in each point.                                          ____
  701.  
  702.          lastx=0;                           //  The first coordinate is relative to 0.    ____
  703.          startPoint = 0;                    //  Start with the first point in the glyph.  ____
  704.  
  705.          for(i=0;i<numberOfContours;i++)
  706.          {
  707.  
  708.             // ____ Find the end point of this contour.                                   ____
  709.  
  710.             endPoint = endPtsOfContours[i];
  711.  
  712.             // ____ Store the number of points in this contour.                           ____
  713.  
  714.             glyphs[gi].contours[i].numPoints = endPoint-startPoint+1;
  715.  
  716.             // ____ Allocate space for the points in this contour.                        ____
  717.  
  718.             glyphs[gi].contours[i].points = new TTPoint[endPoint-startPoint+1];
  719.             if(!glyphs[gi].contours[i].points)
  720.             {
  721.                cout<<"ERROR: Out of memory."<<endl;
  722.                exit(1);
  723.             }
  724.  
  725.             // ____ Get each point in this contour.  Coordinates in the font file are     ____
  726.             // ____ indexed according to position in the entire glyph, while the          ____
  727.             // ____ coordinates stored are indexed according to their position in the     ____
  728.             // ____ current contour.  'startPoint' and 'endPoint' are glyph indexes, and  ____
  729.             // ____ j is the index into the current contour.                              ____
  730.  
  731.             // ____ Process X-Coordinates.                                                ____
  732.  
  733.             for(j=startPoint;j<=endPoint;j++)
  734.             {
  735.                // ____ Get the current flag.                                              ____
  736.  
  737.                currentFlag = flags[j];
  738.  
  739.                // ____ If bit zero in the flag is set then this point is an on-curve      ____
  740.                // ____ point, if not, then it is an off-curve point.                      ____
  741.  
  742.                if(isBitSet(currentFlag,0))
  743.                   glyphs[gi].contours[i].points[j-startPoint].type = ON_CURVE;
  744.                else
  745.                   glyphs[gi].contours[i].points[j-startPoint].type = OFF_CURVE;
  746.  
  747.                // ____ First we check to see if bit one is set.  This would indicate that ____
  748.                // ____ the corresponding coordinate data in the table is 1 byte long.     ____
  749.                // ____ If the bit is not set, then the coordinate data is 2 bytes long.   ____
  750.  
  751.                if(isBitSet(currentFlag,1))
  752.                {
  753.                   // ____ Read in one byte.                                               ____
  754.  
  755.                   xByte = fontdata[pos];pos++;
  756.  
  757.                   // ____ In this case, bit four is the sign of the byte just read in.    ____
  758.  
  759.                   if(isBitSet(currentFlag,4))
  760.                   {
  761.                      glyphs[gi].contours[i].points[j-startPoint].x = xByte;
  762.                      lastx = xByte;
  763.                   }
  764.                   else
  765.                   {
  766.                      glyphs[gi].contours[i].points[j-startPoint].x = -xByte;
  767.                      lastx = -xByte;
  768.                   }
  769.                }
  770.                else
  771.                {
  772.                   // ____ If bit four is set, then this coordinate is the same as the     ____
  773.                   // ____ last one, so the relative offset (of zero) is stored.  If bit   ____
  774.                   // ____ is not set, then read in two bytes and store it as a signed     ____
  775.                   // ____ value.                                                          ____
  776.  
  777.                   if(isBitSet(currentFlag,4))
  778.                   {
  779.                      glyphs[gi].contours[i].points[j-startPoint].x = 0;
  780.                      lastx=0;
  781.                   }
  782.                   else
  783.                   {
  784.                      xWord=toSHORT(fontdata[pos],fontdata[pos+1]);pos+=2;
  785.                      glyphs[gi].contours[i].points[j-startPoint].x = xWord;
  786.                      lastx = xWord;
  787.                   }
  788.                }
  789.  
  790.             } // END: for each point in contour
  791.  
  792.             // ____ Make the new starting point the one after the current ending point.   ____
  793.  
  794.             startPoint=endPoint+1;
  795.  
  796.          } // END: for each contour
  797.  
  798.  
  799.          lasty=0;                       // The first coordinate is relative to zero.      ____
  800.          startPoint = 0;                // Start with the first coordinate in the glyph.  ____
  801.  
  802.          for(i=0;i<numberOfContours;i++)
  803.          {
  804.             // ____ Find the end point of this contour.                                   ____
  805.  
  806.             endPoint = endPtsOfContours[i];
  807.  
  808.             // ____ Get each point in this contour.  Coordinates in the font file are     ____
  809.             // ____ indexed according to position in the entire glyph, while the          ____
  810.             // ____ coordinates stored are indexed according to their position in the     ____
  811.             // ____ current contour.  'startPoint' and 'endPoint' are glyph indexes, and  ____
  812.             // ____ j is the index into the current contour.                              ____
  813.  
  814.             // ____ Process Y-Coordinates.                                                ____
  815.  
  816.             for(j=startPoint;j<=endPoint;j++)
  817.             {
  818.                // ____ Get the current flag.                                              ____
  819.  
  820.                currentFlag = flags[j];
  821.  
  822.                // ____ First we check to see if bit two is set.  This would indicate that ____
  823.                // ____ the corresponding coordinate data in the table is 1 byte long.     ____
  824.                // ____ If the bit is not set, then the coordinate data is 2 bytes long.   ____
  825.  
  826.                if(isBitSet(currentFlag,2))
  827.                {
  828.                   // ____ Read in one byte.                                               ____
  829.  
  830.                   yByte = fontdata[pos];pos++;
  831.  
  832.                   // ____ In this case, bit five is the sign of the byte just read in.    ____
  833.  
  834.                   if(isBitSet(currentFlag,5))
  835.                   {
  836.                      glyphs[gi].contours[i].points[j-startPoint].y = yByte;
  837.                      lasty = yByte;
  838.                   }
  839.                   else
  840.                   {
  841.                      glyphs[gi].contours[i].points[j-startPoint].y = -yByte;
  842.                      lasty = -yByte;
  843.                   }
  844.                }
  845.                else
  846.                {
  847.                   // ____ If bit five is set, then this coordinate is the same as the     ____
  848.                   // ____ last one, so the relative offset (of zero) is stored.  If bit   ____
  849.                   // ____ is not set, then read in two bytes and store it as a signed     ____
  850.                   // ____ value.                                                          ____
  851.  
  852.                   if(isBitSet(currentFlag,5))
  853.                   {
  854.                      glyphs[gi].contours[i].points[j-startPoint].y = 0;
  855.                      lasty=0;
  856.                   }
  857.                   else
  858.                   {
  859.                      yWord=toSHORT(fontdata[pos],fontdata[pos+1]);pos+=2;
  860.                      glyphs[gi].contours[i].points[j-startPoint].y = yWord;
  861.                      lasty = yWord;
  862.                   }
  863.                }
  864.  
  865.             } // END: for each point in contour
  866.  
  867.             // ____ Make the new starting point the one after the current ending point.   ____
  868.  
  869.             startPoint = endPoint+1;
  870.  
  871.          } // END: for each contour in glyph
  872.  
  873.          delete endPtsOfContours;
  874.          delete flags;
  875.  
  876.       } // END: if not a composite.
  877.  
  878.    } // END: for each glyph.
  879.  
  880.    // ____ Finally, change the relative coordinates we just saved into absolute.          ____
  881.  
  882.    for(i=0;i<numGlyphs;i++)
  883.    {
  884.       tx=0;ty=0;
  885.       if(glyphs[i].numContours>0)
  886.       {
  887.          for(j=0;j<glyphs[i].numContours;j++)
  888.          {
  889.             for(k=0;k<glyphs[i].contours[j].numPoints;k++)
  890.             {
  891.                tx+=glyphs[i].contours[j].points[k].x;
  892.                ty+=glyphs[i].contours[j].points[k].y;
  893.                glyphs[i].contours[j].points[k].x=tx;
  894.                glyphs[i].contours[j].points[k].y=ty;
  895.             }
  896.          }
  897.       }
  898.    }
  899.  
  900. }
  901.  
  902.  
  903.  
  904. void TTFont::Print(void)
  905. {
  906.    LONG i,j,k;
  907.  
  908.    cout<<"----------------------------------------------------------------"<<endl;
  909.    cout<<"                       Font Information                   "<<endl;
  910.    cout<<"----------------------------------------------------------------"<<endl;
  911.    cout<<                                     endl;
  912.    cout<<" Family:            " <<Family()                                 <<endl;
  913.    cout<<" Subfamily:         " <<Subfamily()                              <<endl;
  914.    cout<<" Full Name:         " <<FullName()                               <<endl;
  915.    cout<<" Version:           " <<Version()                                <<endl;
  916.    cout<<" Postscript Name:   " <<PSName()                                 <<endl;
  917.    cout<<" Copyright:         " <<Copyright()                              <<endl;
  918.    cout<<" Trademark:         " <<Trademark()                              <<endl;
  919.    cout<<                                                                    endl;
  920.    cout<<"Units per Em Square:  " <<unitsPerEm                             <<endl;
  921.    cout<<"Number of Glyphs in this Font: " <<numGlyphs                     <<endl;
  922.    cout<<"Maximum Number of Points in a Glyph: " <<maxPoints               <<endl;
  923.    cout<<"Maximum Number of Contours in a Glyph: " <<maxContours           <<endl;
  924.    cout<<                                                                    endl;
  925.    cout<<"Character Mappings:"                                             <<endl;
  926.  
  927.    for(i=0;i<256;i++)
  928.       cout<<" Character: "<<i<<" --- Glyph Index: "<<CharacterMap(i)<<endl;
  929.    cout<<endl;
  930.  
  931.    cout<<"Glyphs:"<<endl;
  932.    for(i=0;i<numGlyphs;i++)
  933.    {
  934.       cout<<"Index: "<<i<<" Contours: "<<glyphs[i].numContours<<endl;
  935.       for(j=0;j<glyphs[i].numContours;j++)
  936.       {
  937.          cout<<"   Contour: "<<j<<" Points: "<<glyphs[i].contours[j].numPoints<<endl;
  938.          for(k=0;k<glyphs[i].contours[j].numPoints;k++)
  939.          {
  940.             if (glyphs[i].contours[j].points[k].type==ON_CURVE)
  941.                cout<<"     ON_CURVE Point: (";
  942.             else
  943.                cout<<"    OFF_CURVE Point: (";
  944.             cout<<glyphs[i].contours[j].points[k].x<<",";
  945.             cout<<glyphs[i].contours[j].points[k].y<<")"<<endl;
  946.          }
  947.       }
  948.    }
  949.  
  950.  
  951. }
  952.  
  953.  
  954.